package com.example.basicsecurity.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

import static com.example.basicsecurity.constant.Constant.*;
import static org.springframework.security.config.Customizer.withDefaults;

import javax.sql.DataSource;

/**
 * @author 罗俊华
 * @date 2021/10/9 - 11:19 上午
 */
@Slf4j
@Order(SecurityProperties.BASIC_AUTH_ORDER - 10)
@EnableWebSecurity
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * 使用 @Autowired 来将 AuthenticationManagerBuilder 注入方法进行配置
     * 将成为全局的 AuthenticationManager 配置
     *
     * @param builder
     * @throws Exception
     */
    @Autowired
    public void initialize(AuthenticationManagerBuilder builder) throws Exception {


        PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        builder.inMemoryAuthentication()
                .withUser("luo")
                .password(passwordEncoder.encode("1234"))
                .authorities(CODING_AUTHORITY,SLEEP_AUTHORITY)
                .roles(ROLE_ADMIN)

                .and()
                .withUser("yan")
                .password(passwordEncoder.encode("1234"))
                .roles(ROLE_USER)


                .and()
                .withUser("wang")
                .password(passwordEncoder.encode("1234"))
                .roles(ROLE_ADMIN);
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }


    /*
     * 覆盖父类方法之后，这样的配置则只是局部的配置
     * 这样的局部配置将会是全局配置旗下的子配置
     * @param builder
     * @throws Exception
     */
    /*@Override
    public void configure(AuthenticationManagerBuilder builder) throws Exception {
        builder.inMemoryAuthentication().withUser("dave")
                .password("secret").roles("USER");
    }*/


    /**
     * 新增了一条spring security 的过滤器链，并且其优先于 fallback 过滤器链执行
     * fallback 的过滤器链的优先级为 @Order(SecurityProperties.BASIC_AUTH_ORDER)
     *
     * @param http
     * @throws Exception
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 这里定义的拦截顺序非常重要
        http.authorizeRequests()
                .antMatchers(LOGIN_PAGE,LOGIN_PROCESSING_URL).permitAll()
                .antMatchers("/**")
                .hasRole(ROLE_ADMIN)

                .and()
                .logout()
                .logoutUrl(LOGOUT_URL)
                .logoutSuccessUrl(LOGIN_PAGE)  //退出登陆成功之后，跳转到登陆页面

                .and()

                // 使用 http 自带的网页弹出登陆框进行登陆 https://docs.spring.io/spring-security/reference/servlet/authentication/passwords/basic.html
                //.httpBasic(withDefaults());
                .formLogin()

                //声明了我们提供的自定义登录页面的路径
                //当SpringSecurity断定用户没有认证并且需要登录的时候，它就会将用户重定向到该路径
                .loginPage(LOGIN_PAGE) // 必须以 '/' 开头，然后此路径要对应一个 controller

                // 设置用户点击登陆时，验证用户名和密码的url地址
                // 注意：html 中的form表单也必须是这个地址
                // 在 loginController 中使用了 ModelAndView 将此常量传递给了 thymeleaf 模版引擎
                .loginProcessingUrl(LOGIN_PROCESSING_URL)
                .defaultSuccessUrl(HELLO)   // 默认登陆成功之后跳转的地址
                .usernameParameter("username")
                .passwordParameter("password")


                ;

    }
}
